﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using SimpleServiceBus.Endpoint;

namespace SimpleServiceBus.Bus.MessageManagement.Serialization
{
    public class DataContractMessageSerializer : EndpointServiceBase, IMessageSerializer
    {
        private DataContractSerializer _xmlMessageSerializer;
        private Type[] _knownTypes;

        public Type[] KnownTypes
        {
            get
            {
                return _knownTypes;
            }
            set
            {
                if (IsRunning)
                    throw new InvalidOperationException("KnownTypes must be set prior to starting this service.");
                _knownTypes = value;
            }
        }

        public IDataContractSurrogate DataContractSurrogate { get; set; }

        #region IMessageSerializer Members

        public void Serialize(object message, Stream stream)
        {
            _xmlMessageSerializer.WriteObject(stream, message);
        }

        public object Deserialize(Stream stream)
        {
            return _xmlMessageSerializer.ReadObject(stream);
        }

        #endregion

        private void Initialize()
        {
            var messageTypes = new List<Type> {typeof (object)};
            
            if (_knownTypes != null)
                messageTypes.AddRange(_knownTypes);

            var msgMgr = ServiceManager.GetService<IMessageTypeManagementService>();
            if (msgMgr != null)
            {
                messageTypes.AddRange(msgMgr.GetRegisteredMessageTypes());
            }

            _xmlMessageSerializer = new DataContractSerializer(typeof(object), messageTypes.ExtractSerializableTypes(),
                int.MaxValue, false, true, DataContractSurrogate);
        }

        protected override void ShutDownService()
        {
            _xmlMessageSerializer = null;
        }

        protected override void StartService()
        {
            Initialize();
        }
    }
}